package com.management.demo.controller.wx;

import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.management.demo.common.ListNestIntTypeReference;
import com.management.demo.common.dto.PageDTO;
import com.management.demo.common.vo.PageVO;
import com.management.demo.domain.wx.Amount;
import com.management.demo.domain.wx.Goods;
import com.management.demo.domain.wx.Taste;
import com.management.demo.dto.wx.GoodsDTO;
import com.management.demo.dto.wx.GoodsQueryDTO;
import com.management.demo.service.AmountService;
import com.management.demo.service.GoodsService;
import com.management.demo.service.TasteService;
import com.management.demo.vo.wx.AmountVO;
import com.management.demo.vo.wx.CategoryGoodsVO;
import com.management.demo.vo.wx.GoodsVO;
import com.management.demo.vo.wx.TasteAmountVO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Tag(name = "商品接口")
@RestController
@RequestMapping("wx/goods")
public class WXGoodsController {

    @Autowired
    private GoodsService goodsService;

    @Autowired
    private AmountService amountService;

    @Autowired
    private TasteService tasteService;

    private final Cache<String, Map<Integer, String>> tasteMapCache = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.MINUTES).build();

    private final Cache<String, Map<Integer, String>> amountMapCache = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.SECONDS).build();

    private final Cache<String, List<CategoryGoodsVO>> goodsCache = CacheBuilder.newBuilder()
            .expireAfterWrite(60, TimeUnit.SECONDS).build();

    @Operation(summary = "分页查询商品")
    @PostMapping("page")
    public SaResult page(@RequestBody GoodsQueryDTO goodsQueryDTO) {
        String name = goodsQueryDTO.getName();
        Integer status = goodsQueryDTO.getStatus();
        Integer categoryId = goodsQueryDTO.getCategoryId();
        Integer currentPage = goodsQueryDTO.getCurrentPage();
        Integer pageSize = goodsQueryDTO.getPageSize();

        LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<Goods>()
                .like(StringUtils.isNotBlank(name), Goods::getName, name)
                .eq(status != null, Goods::getStatus, status)
                .eq(categoryId != null, Goods::getCategoryId, categoryId)
                .orderByAsc(Arrays.asList(Goods::getCategoryId, Goods::getSort));
        Page<Goods> goodsPage = goodsService.page(new Page<>(currentPage, pageSize), queryWrapper);

        Map<Integer, String> tasteMap = getTasteMap();
        Map<Integer, String> amountMap = getAmountMap();

        PageVO<GoodsVO> goodsPageVO = PageDTO.getPageVO(goodsPage, item -> copyGoodsVO(item, tasteMap, amountMap));
        return SaResult.ok().setData(goodsPageVO);
    }

    @Operation(summary = "查询所有商品")
    @PostMapping("list")
    public SaResult list(@RequestBody GoodsQueryDTO goodsQueryDTO) {
        List<CategoryGoodsVO> result;
        try {
            result = goodsCache.get("goods", () -> {
                List<CategoryGoodsVO> categoryGoodsVOList = new ArrayList<>();
                Integer status = goodsQueryDTO.getStatus();
                List<Goods> records = goodsService.list(new LambdaQueryWrapper<Goods>()
                        .eq(status != null, Goods::getStatus, status)
                        .orderByAsc(Arrays.asList(Goods::getCategoryId, Goods::getSort)));
                List<GoodsVO> goodsVOList = copyGoods(records);
                // 把商品按照类型分类
                Map<Integer, List<GoodsVO>> goodsByType = goodsVOList.stream().collect(Collectors.groupingBy(GoodsVO::getCategoryId));
                goodsByType.forEach((key, value) -> {
                    CategoryGoodsVO categoryGoodsVO = new CategoryGoodsVO();
                    categoryGoodsVO.setCategoryId(key);
                    categoryGoodsVO.setGoodsList(value);
                    categoryGoodsVOList.add(categoryGoodsVO);
                });
                return categoryGoodsVOList;
            });
        } catch (Exception e) {
            e.printStackTrace();
            return SaResult.error("查询商品列表失败");
        }
        return SaResult.ok().setData(result);
    }

    @Operation(summary = "新增/修改商品信息")
    @PostMapping("createOrEdit")
    public SaResult createOrEdit(@RequestBody GoodsDTO goodsDTO) {
        Goods goods = BeanUtil.copyProperties(goodsDTO, Goods.class);
        boolean result = goodsService.saveOrUpdate(goods);
        return SaResult.ok().setData(result);
    }

    @Operation(summary = "根据id获取商品信息")
    @GetMapping("getById/{id}")
    public SaResult getById(@Parameter(description = "商品id") @PathVariable Integer id) {
        Goods goods = goodsService.getById(id);
        Map<Integer, String> tasteMap = getTasteMap();
        Map<Integer, String> amountMap = getAmountMap();
        try {
            GoodsVO goodsVO = copyGoodsVO(goods, tasteMap, amountMap);
            return SaResult.ok().setData(goodsVO);
        } catch (Exception e) {
            e.printStackTrace();
            return SaResult.error("查询商品列表失败");
        }
    }

    @Operation(summary = "删除商品信息")
    @DeleteMapping("remove/{id}")
    public SaResult remove(@Parameter(description = "商品id") @PathVariable Integer id) {
        boolean result = goodsService.removeById(id);
        return SaResult.ok().setData(result);
    }

    @Operation(summary = "修改商品展示状态")
    @PostMapping("changeStatus/{id}/{status}")
    public SaResult changeStatus(@Parameter(description = "商品id") @PathVariable Integer id, @Parameter(description = "是否展示") @PathVariable Integer status) {
        UpdateWrapper<Goods> categoryUpdateWrapper = new UpdateWrapper<>();
        categoryUpdateWrapper.set("status", status);
        categoryUpdateWrapper.eq("id", id);
        boolean result = goodsService.update(categoryUpdateWrapper);
        return SaResult.ok().setData(result);
    }


    // 获取口味列表
    private Map<Integer, String> getTasteMap() {
        Map<Integer, String> tasteMap = new HashMap<>();
        try {
            tasteMap = tasteMapCache.get("tasteMap", () ->
                    tasteService.list().stream().collect(Collectors.toMap(Taste::getId, Taste::getName)));
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return tasteMap;
    }

    // 获取用量列表
    private Map<Integer, String> getAmountMap() {
        Map<Integer, String> amountMap = new HashMap<>();
        try {
            amountMap = amountMapCache.get("amountMap", () ->
                    amountService.list().stream().collect(Collectors.toMap(Amount::getId, Amount::getName)));
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return amountMap;
    }

    // copy 商品列表
    private List<GoodsVO> copyGoods(List<Goods> records) {
        List<GoodsVO> goodsVOList = new ArrayList<>();
        Map<Integer, String> tasteMap = getTasteMap();
        Map<Integer, String> amountMap = getAmountMap();
        for (Goods goods : records) {
            GoodsVO goodsVO = copyGoodsVO(goods, tasteMap, amountMap);
            goodsVOList.add(goodsVO);
        }
        return goodsVOList;
    }

    // copy 商品 排除 specifications 属性 然后自己转换成集合
    private GoodsVO copyGoodsVO(Goods goods, Map<Integer, String> tasteMap, Map<Integer, String> amountMap) {
        GoodsVO goodsVO = BeanUtil.copyProperties(goods, GoodsVO.class, "specifications", "selectedItems", "recommendItems");
        List<List<Integer>> specifications = stringToList(goods.getSpecifications());
        List<List<Integer>> selectedItems = stringToList(goods.getSelectedItems());
        List<List<Integer>> recommendItems = stringToList(goods.getRecommendItems());

        Map<Integer, List<Integer>> groupedSpecifications = groupedData(specifications);
        Map<Integer, List<Integer>> groupedSelectedItems = groupedData(selectedItems);
        Map<Integer, List<Integer>> groupedRecommendItems = groupedData(recommendItems);

        goodsVO.setSpecifications(specifications);
        goodsVO.setSelectedItems(selectedItems);
        goodsVO.setRecommendItems(recommendItems);

        List<TasteAmountVO> tasteAmountList = new ArrayList<>();
        // 遍历分组好的map 拼接数据
        for (Map.Entry<Integer, List<Integer>> groupedSpecificationsEntry : groupedSpecifications.entrySet()) {
            Integer tasteId = groupedSpecificationsEntry.getKey();
            // 构建口味VO
            TasteAmountVO tasteAmountVO = new TasteAmountVO();
            tasteAmountVO.setId(tasteId);
            tasteAmountVO.setName(tasteMap.get(tasteId));

            // 获取当前口味对应的选中和推荐用量列表
            List<Integer> selectedAmounts = groupedSelectedItems.getOrDefault(tasteId, Collections.emptyList());
            List<Integer> recommendAmounts = groupedRecommendItems.getOrDefault(tasteId, Collections.emptyList());
            List<AmountVO> amountVOs = new ArrayList<>();
            for (Integer amountId : groupedSpecificationsEntry.getValue()) {
                String amountName = amountMap.get(amountId);
                boolean containsSelected = selectedAmounts.contains(amountId);
                boolean containsRecommend = recommendAmounts.contains(amountId);
                amountVOs.add(new AmountVO(amountId, amountName, containsSelected, containsRecommend, tasteId));
            }
            tasteAmountVO.setAmountList(amountVOs);
            tasteAmountList.add(tasteAmountVO);
        }
        goodsVO.setAmountList(tasteAmountList);
        return goodsVO;
    }

    // 按照口味和用量分组 key=口味id value=用量id集合
    private Map<Integer, List<Integer>> groupedData(List<List<Integer>> data) {
        Map<Integer, List<Integer>> groupedData = new HashMap<>();
        for (List<Integer> item : data) {
            Integer tasteId = item.get(0);
            Integer amountId = item.get(1);
            groupedData.computeIfAbsent(tasteId, k -> new ArrayList<>()).add(amountId);
        }
        return groupedData;
    }

    // 将数据库存储的 string 转换为前端可读取的 list
    private List<List<Integer>> stringToList(String data) {
        return JSONUtil.parseArray(data).toBean(new ListNestIntTypeReference());
    }
}
